package com.example.lottery.service.impl;


import cn.hutool.crypto.digest.DigestUtil;
import com.example.lottery.common.errorcode.ServiceErrorCodeConstants;
import com.example.lottery.common.exception.ServiceException;
import com.example.lottery.common.utils.JWTUtil;
import com.example.lottery.common.utils.RegexUtil;
import com.example.lottery.controller.param.UserLogin;
import com.example.lottery.controller.param.UserLoginMessage;
import com.example.lottery.controller.param.UserLoginPassword;
import com.example.lottery.controller.param.UserRegisterParam;
import com.example.lottery.dao.dataobject.Encrypt;
import com.example.lottery.dao.dataobject.UserDO;
import com.example.lottery.dao.mapper.UserMapper;
import com.example.lottery.service.UserService;
import com.example.lottery.service.dto.UserDTO;
import com.example.lottery.service.dto.UserLoginDTO;
import com.example.lottery.service.dto.UserRegisterDTO;
import com.example.lottery.service.enums.UserIdentityEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class UserServicelmpl implements UserService {
    @Autowired
    private VerificationCodeServiceImpl verificationCodeService;

    @Autowired
    private UserMapper userMapper;

    @Override
    public UserRegisterDTO register(UserRegisterParam param) {
        //校验注册信息
        checkRegisterInfo(param);

        //加密私密数据(构造dao层数据请求)
        UserDO userDo = new UserDO();
        userDo.setUserName(param.getName());
        userDo.setIdentity(param.getIdentity());
        userDo.setEmail(param.getMail());
        userDo.setPhoneNumber(new Encrypt(param.getPhoneNumber()));//使用对称加密AES

        if (StringUtils.hasText(param.getIdentity())) {
            userDo.setPassword(DigestUtil.sha256Hex(param.getPassword()));
        }

        //插入数据
        userMapper.insert(userDo);

        //构造返回
        UserRegisterDTO dto = new UserRegisterDTO();
        dto.setUserId(userDo.getId());
        return dto;

    }

    @Override
    public UserLoginDTO login(UserLogin param) {
        UserLoginDTO dto ;

        //类型转换和检查 java14以上
        if (param instanceof UserLoginPassword loginPassowrd) {
            //密码登录流程
            dto = loginByUserPassoword(loginPassowrd);
        }else if (param instanceof UserLoginMessage loginMessage) {
            //验证码登录流程
            dto = loginByUserMessage(loginMessage);
        }else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_INFO_NOT_EXIST);
        }
        return dto;
    }

    @Override
    public List<UserDTO> findBaseUserInfo(UserIdentityEnum identity) {
        String identityString = null == identity ? null : identity.name();
        //查表
        List<UserDO> userDOList = userMapper.selectUserListByIdentity(identityString);

        //让userDOList使用stream流转换成userDTOList
        List<UserDTO> userDTOList = userDOList.stream().map(userDO -> {
            UserDTO dto = new UserDTO();
            dto.setUserId(userDO.getId());
            dto.setEmail(userDO.getEmail());
            dto.setUserName(userDO.getUserName());
            dto.setPhoneNumber(userDO.getPhoneNumber().getValue());
            dto.setIdentity(UserIdentityEnum.getByName(userDO.getIdentity()));
            return dto;
        }).collect(Collectors.toList());
        return userDTOList;
    }

    private UserLoginDTO loginByUserMessage(UserLoginMessage loginMessage) {
        //校验邮箱是否正确
        if (!RegexUtil.checkMail(loginMessage.getLoginEmail())) {
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_ERROR);
        }
        //获取用户数据
        UserDO userDo = userMapper.selectByMail(loginMessage.getLoginEmail());
        if (userDo == null) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        }else if (!StringUtils.hasText(loginMessage.getMandatoryIdentity())
        || !userDo.getIdentity().equalsIgnoreCase(loginMessage.getMandatoryIdentity())) {
            //身份认证
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }

        //校验验证码
        String code = verificationCodeService.getVerificationCode(loginMessage.getLoginEmail());
        if (!loginMessage.getVerifyCode().equals(code)) {
            throw new ServiceException(ServiceErrorCodeConstants.VERIFICATION_CODE_ERROR);
        }

        //JWT
        Map<String,Object> claim = new HashMap<String,Object>();
        claim.put("id",userDo.getId());
        claim.put("identity",userDo.getIdentity());
        String token = JWTUtil.genJwt(claim);

        UserLoginDTO userLoginDTO = new UserLoginDTO();
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentity(UserIdentityEnum.getByName(userDo.getIdentity()));
        return userLoginDTO;

    }

    /**
     * 管理员密码登录
     * @param loginPassowrd
     * @return
     */
    private UserLoginDTO loginByUserPassoword(UserLoginPassword loginPassowrd) {
        UserDO userDo ;
        if (RegexUtil.checkMail(loginPassowrd.getLoginName())) {
            //检查账号是否存在(邮箱即为账号)
            userDo = userMapper.selectByMail(loginPassowrd.getLoginName());
        }else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_NOT_EXIST);
        }

        //校验信息
        if (userDo == null) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        }else if (!StringUtils.hasText(loginPassowrd.getMandatoryIdentity()) &&
        !loginPassowrd.getMandatoryIdentity().equalsIgnoreCase(userDo.getIdentity())) {
            //强制身份登录，校验身份
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }else if (!DigestUtil.sha256Hex(loginPassowrd.getPassword()).equals(userDo.getPassword())) {
            //校验密码
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }

        //JWT
        Map<String,Object> claim = new HashMap<String,Object>();
        claim.put("id",userDo.getId());
        claim.put("identity",userDo.getIdentity());
        //通过JWT工具类来获取jwt的token
        String token = JWTUtil.genJwt(claim);

        UserLoginDTO userLoginDTO = new UserLoginDTO();
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentity(UserIdentityEnum.getByName(userDo.getIdentity()));
        return userLoginDTO;
    }

    private void checkRegisterInfo(UserRegisterParam param) {
        if (param == null) {
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_INFO_IS_EMPTY);
        }


        //校验邮箱格式xxx@xxx.xxx
        if (!RegexUtil.checkMail(param.getMail())) {
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_ERROR);
        }


        //校验手机号码格式
        if (!RegexUtil.checkMobile(param.getPhoneNumber())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }

        //校验身份信息
        if (UserIdentityEnum.getByName(param.getIdentity()) == null) {
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }

        //校验管理员密码
        if (param.getIdentity().equalsIgnoreCase(UserIdentityEnum.ADMIN.name())
            && !StringUtils.hasText(param.getPassword())) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_IS_EMPTY);
        }

        //密码校验,必须6位
        if (StringUtils.hasText(param.getPassword()) && !RegexUtil.checkPassword(param.getPassword())) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }



        //校验邮箱是否被使用
        if (checkMailUsed(param.getMail())) {
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_USED);
        }


        //校验手机号码是否被使用
        if (checkPhoneNumber(new Encrypt(param.getPhoneNumber()))) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }


    }

    private boolean checkPhoneNumber(Encrypt phoneNumber) {
        int count = userMapper.countByPhoneNumber(phoneNumber);
        return count > 0;
    }

    private boolean checkMailUsed(String mail) {
        int count = userMapper.countByMail(mail);
        return count > 0;
    }
}
